package com.opta.service;

import com.opta.entity.*;
import org.apache.commons.lang3.StringUtils;
import org.optaplanner.core.api.solver.Solver;
import org.optaplanner.core.api.solver.SolverFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 2 * @Author: GuanChong
 * 3 * @Date: 2020/10/12 11:04
 * 4 * @Desc: 引擎计算Service
 */
@Service
public class OptaService {
    private final Logger log = LoggerFactory.getLogger(OptaService.class);

    /**
     * 引擎计算函数
     *
     * @param ordersAndLines 订单和线体
     */
    public void orderAndSupplyService(OrdersAndLines ordersAndLines, String type) {
        //引擎实现
        solve(ordersAndLines, type);
    }


    /**
     * Solver
     *
     * @param ordersAndLines 订单和线体
     */
    private void solve(OrdersAndLines ordersAndLines, String type) {
        //region 基本信息
        //公司
        String company = ordersAndLines.getCompany();
        //版本号
        String versionName = ordersAndLines.getVersionName();
        //待排任务集合
        List<TaskOrder> taskOrders = ordersAndLines.getOrders();
        //线体产能集合
        List<Line> lines = ordersAndLines.getLines();
        //班组可生产机型(物料)
        Map<String, Map<String, Double>> materProdTeamMap = ordersAndLines.getMaterialProducibleTeamMap();
        //endregion
        //region 构建引擎
        //SolverFactory - 加载求解配置文件
        if (StringUtils.isBlank(type)) {
            //EasyScore计算方式
            type = "opta/OrderEasyScoreSolutionRules.xml";
            log.info("@@@@@@@@@@@@@@@@@@@@@@@@采用简单计算模式");
        } else if ("Incremental".equals(type)) {
            //IncrementalScore计算方式
            type = "opta/OrderIncrementalScoreSolutionRules.xml";
            log.info("@@@@@@@@@@@@@@@@@@@@@@@@采用增量计算模式");
        }

        SolverFactory<OrderSolution> solverFactory = SolverFactory.createFromXmlResource(type);
        //Solver - 创建求解器
        Solver<OrderSolution> solver = solverFactory.buildSolver();
        //添加监听器 用于监听得到的最优结果
//        solver.addEventListener(new OrderSolverEventListener());
        //处理数据需要的数据 尽量在引擎外计算
        Map<String, Map<LocalDate, Integer>> lineSupplyMap = new HashMap<>(ordersAndLines.getLines().size());

        Map<String, List<Line>> singleMap = ordersAndLines.getLines().stream().collect(Collectors.groupingBy(Line::getTeam));

//        for (Line line : ordersAndLines.getLines()) {
//            //这个班组在这天有多少小时可以用
//            List<Line> linesGroup = singleMap.get(line.getTeam());
//            Map lineV = new HashMap(16);
//            if (linesGroup != null) {
//                linesGroup.forEach(s -> {
//                    lineV.put(s.getDate(), s.getCapacity());
//                });
//                lineSupplyMap.put(line.getTeam(), lineV);
//            }
//        }

        //endregion
        SolutionResult.Result result = optaCal(taskOrders, lines, solver, company, versionName, materProdTeamMap, lineSupplyMap);
    }


    private SolutionResult.Result optaCal(List<TaskOrder> orderDTOList, List<Line> lines, Solver<OrderSolution> solver, String company, String versionName, Map<String, Map<String, Double>> materProdTeamMap, Map<String, Map<LocalDate, Integer>> lineSupplyMap) {
        //按照seq 序号排序 类似优先级
        orderDTOList.sort(Comparator.comparing(TaskOrder::getSeq, Comparator.nullsLast(Integer::compareTo)));
        //最优解的ID
        String solutionId = "" + System.currentTimeMillis();

        //将数据传送给引擎 引擎接收到的数据
        OrderSolution taskAssignment = new OrderSolution(solutionId, orderDTOList, lines, materProdTeamMap, lineSupplyMap);
        //Solved
        OrderSolution solution = solver.solve(taskAssignment);
        log.info("执行分数为:" + solution.getScore());
        log.info("执行结果为:" + solution.getOrders().size());
        //作废
//        log.info("执行结果 班组产能:" + solution.getLineSupplyMap());


        List<Line> scheduledLines = solution.getOrders().stream().map(TaskOrder::getLine).collect(Collectors.toList());
        scheduledLines = scheduledLines.stream().filter(s -> s != null && s.getLineId() != null).collect(Collectors.toList());
        List<Line> scheduledLinesF = scheduledLines;
        List<Line> emptyProductions = lines.stream().filter(s -> !scheduledLinesF.contains(s)).distinct().collect(Collectors.toList());
//        log.info("执行结果 空产的班组:" + emptyProductions);


        //（上次已保订单）引擎结果 结束计算后的最优结果
        SolutionResult.Result result = SolutionResult.getAndRemove(solutionId);

        //持久化 保存最优解
        return result;
    }


}
